package com.phantom.irpc.framework.core.server;

import com.phantom.irpc.framework.core.common.RpcDecoder;
import com.phantom.irpc.framework.core.common.RpcEncoder;
import com.phantom.irpc.framework.core.common.config.PropertiesBootstrap;
import com.phantom.irpc.framework.core.common.config.ServerConfig;
import com.phantom.irpc.framework.core.common.utils.CommonUtils;
import com.phantom.irpc.framework.core.registry.RegistryService;
import com.phantom.irpc.framework.core.registry.URL;
import com.phantom.irpc.framework.core.registry.zookeeper.ZookeeperRegister;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import static com.phantom.irpc.framework.core.common.cache.CommonServerCache.PROVIDER_CLASS_MAP;
import static com.phantom.irpc.framework.core.common.cache.CommonServerCache.PROVIDER_URL_SET;

public class Server {

    private static EventLoopGroup bossGroup = null;
    private static EventLoopGroup workerGroup = null;

    public ServerConfig serverConfig;

    private RegistryService registryService;

    public ServerConfig getServerConfig() {
        return serverConfig;
    }

    public void setServerConfig(ServerConfig serverConfig) {
        this.serverConfig = serverConfig;
    }

    public void startApplication() throws InterruptedException {
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .option(ChannelOption.SO_BACKLOG, 1024)
                        .option(ChannelOption.SO_SNDBUF, 16 * 1024)
                        .option(ChannelOption.SO_RCVBUF, 16 * 1024)
                        .option(ChannelOption.SO_KEEPALIVE, true)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                System.out.println("初始化provider过程");
                                ch.pipeline().addLast(new RpcEncoder());
                                ch.pipeline().addLast(new RpcDecoder());
                                ch.pipeline().addLast(new ServerHandler());
                            }
                        });
        serverBootstrap.bind(serverConfig.getServerPort()).sync();
    }

    public void initServerConfig() {
        ServerConfig serverConfig = PropertiesBootstrap.loadServerConfigFromLocal();
        this.setServerConfig(serverConfig);
    }

    /**
     * 暴露服务信息
     *
     * @param serviceBean
     */
    public void exportService(Object serviceBean) {
        if (serviceBean.getClass().getInterfaces().length == 0) {
            throw new RuntimeException("service must had interfaces!");
        }
        Class[] classes = serviceBean.getClass().getInterfaces();
        if (classes.length > 1) {
            throw new RuntimeException("service must only had one interfaces!");
        }
        if (registryService == null) {
            registryService = new ZookeeperRegister(serverConfig.getRegisterAddr());
        }
        // 默认选择该对象的第一个实现接口
        Class interfaceClass = classes[0];
        PROVIDER_CLASS_MAP.put(interfaceClass.getName(), serviceBean);
        URL url = new URL();
        url.setServiceName(interfaceClass.getName());
        url.setApplicationName(serverConfig.getApplicationName());
        url.addParameter("host", CommonUtils.getIpAddress());
        url.addParameter("port", String.valueOf(serverConfig.getServerPort()));
        PROVIDER_URL_SET.add(url);
    }


    /**
     * 将服务端的具体服务都暴露到注册中心，方便客户端进行调用
     */
    public void batchExportUrl(){
        Thread task = new Thread(() -> {
            try {
                Thread.sleep(2500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (URL url : PROVIDER_URL_SET) {
                // 将服务提供者url注册到注册中心
                registryService.register(url);
            }
        });
        task.start();
    }

    public void registryService(Object serviceBean) {
        Class[] classes = serviceBean.getClass().getInterfaces();
        if (classes.length == 0) {
            throw new RuntimeException("service must have interfaces!");
        }
        if (classes.length > 1) {
            throw new RuntimeException("service must only have one interface!");
        }
        Class interfaceClass = classes[0];
        // 需要注册的对象统一在一个map集合中管理
        PROVIDER_CLASS_MAP.put(interfaceClass.getName(), interfaceClass);

    }
}
